package com.cj.spring;

import com.cj.spring.annotation.Component;
import com.cj.spring.annotation.ComponentScan;
import com.cj.spring.annotation.Scope;
import com.cj.spring.config.BeanDefinition;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author chan
 * @dateTime 2022/10/25  17:16:58
 */
public class ApplicationContext {

    private Class aClass;

    private Map<String, BeanDefinition> beanDefinition = new HashMap<String, BeanDefinition>();

    private ConcurrentHashMap<String, Object> singletonCache = new ConcurrentHashMap<String, Object>();

    public ApplicationContext() {
    }

    public ApplicationContext(Class aClass) {
        this.aClass = aClass;

        //scan扫描bean    注册到beandefinitionMap
        initContainer(aClass);

        //保存一级缓存
        saveSingletonCache();

    }

    private void saveSingletonCache() {
        for (Map.Entry<String, BeanDefinition> beanMap : beanDefinition.entrySet()) {
            BeanDefinition value = beanMap.getValue();
            if (!value.getLazyInit()) {
                try {
                    Constructor constructor = value.getaClass().getConstructor();
                    Object o = constructor.newInstance();
                    singletonCache.put(beanMap.getKey(), o);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    private void initContainer(Class aClass) {
        ComponentScan componentScan = (ComponentScan) aClass.getAnnotation(ComponentScan.class);
        if (componentScan != null) {
            if (componentScan.value().equals("")) {
                throw new RuntimeException("classpath not found ");
            }
            String str = componentScan.value().replaceAll("\\.", "/");
            File file = new File(this.getClass().getClassLoader().getResource(str).getPath());
            String parent = file.getPath();
            File fileNew = new File(parent);
            //获取全部File
            //返回目录名加文件名
            //添加过滤器
            File[] strings = fileNew.listFiles();
            for (File fileItem : strings) {
                if (fileItem.isDirectory()) {
                    for (File listFile : fileItem.listFiles()) {
                        getBeanDefinition(componentScan, listFile);
                    }
                }
                getBeanDefinition(componentScan, fileItem);
            }
        }

    }

    private void getBeanDefinition(ComponentScan componentScan, File fileItem) {
        if (fileItem.getPath().lastIndexOf(".class") > 0) {
            String path = fileItem.getPath().replaceAll("/", "\\.");
            String className = path.substring(path.indexOf(componentScan.value()), path.length() - 6);
            Class<?> aClass1 = null;
            try {
                aClass1 = Class.forName(className);
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
            if (aClass1.isAnnotationPresent(Component.class)) {
                Component annotation = aClass1.getAnnotation(Component.class);
                BeanDefinition beanDefinition1 = new BeanDefinition();
                beanDefinition1.setaClass(aClass1);
                beanDefinition1.setLazyInit(false);
                if (aClass1.isAnnotationPresent(Scope.class)) {
                    Scope scope = aClass1.getAnnotation(Scope.class);
                    beanDefinition1.setSingleton(scope.value().equals("") ? "singleton" : scope.value());
                }

                beanDefinition.put(annotation.value(), beanDefinition1);
            }
        }
    }

    public Object getBean(String beanName) {
        BeanDefinition beanDefinition1 = beanDefinition.get(beanName);
        if (beanDefinition1.getLazyInit()) {
            return getObject(beanName, beanDefinition1);
        }
        if (beanDefinition1.getSingleton().equals("singleton")) {
            return singletonCache.get(beanName);
        }
        if (beanDefinition1.getSingleton().equals("property")) {
            return getObject(beanName, beanDefinition1);
        }
        return null;
    }

    private Object getObject(String beanName, BeanDefinition beanDefinition1) {
        Constructor constructor = null;
        try {
            constructor = beanDefinition1.getaClass().getConstructor();
            Object o = constructor.newInstance();
            singletonCache.put(beanName, o);
            return o;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
